Skip to content

perf(phase 4): scope ContentView re-renders + lazy startup - #656

Open
mehmetefeaytas wants to merge 29 commits into
Ebullioscopic:devfrom
mehmetefeaytas:feat/perf-phase-4
Open

perf(phase 4): scope ContentView re-renders + lazy startup#656
mehmetefeaytas wants to merge 29 commits into
Ebullioscopic:devfrom
mehmetefeaytas:feat/perf-phase-4

Conversation

@mehmetefeaytas

@mehmetefeaytas mehmetefeaytas commented Jul 23, 2026

Copy link
Copy Markdown

Phase 4 (final) of the staged performance pass — cuts the idle re-render storm and cold-start cost. Stacked on #655#654#653; merge those first (diff includes them until they land). Conservative, behavior-preserving.

Changes

  • ContentView re-render scoping (ContentView.swift):
    • isNonNotchScreen no longer walks NSScreen.screens on every body evaluation — the result is cached in @State and refreshed only on didChangeScreenParametersNotification / selected-screen change (same value, far fewer scans while music/stats tick).
    • StatsManager is no longer an @ObservedObject of ContentView. It was only used imperatively (updateMonitoringState, statsRowCount reads @Default flags) — never read reactively — while the live stats UI already has its own @ObservedObject in NotchStatsView. Dropping the observation removes the 1 Hz whole-body invalidation without changing behavior.
    • Entangled sections (music/elapsedTime, battery, hover/gesture/animation, notch open/close) intentionally left as-is.
  • Lazy startup (DynamicIslandApp.swift): feature managers with an external/view-tree owner (calendarManager, dndManager, downloadManager, idleAnimationManager) become lazy var; always-on managers with no other owner (bluetoothAudioManager, systemTimerBridge, lockScreenPanelManager) are lazy but materialized one runloop after first frame. Heavy launch work — initializeDefaultAnimations(), applySelectedAppIcon() (disk I/O), playWelcomeSound() — deferred off the first frame. Core managers (vm, coordinator, webcam, extension hosts) stay eager; Defaults migrations and publisher sinks stay eager (correctness/ordering).

Expected gains (estimates — verify with Instruments)

  • Cold-start −20…40% (lazy init + deferred launch); idle CPU further −20…40% (re-render storm gone — compounds with Phase 3). Multi-monitor benefit scales with screen count.

Verify on device

  • Instruments Time Profiler at launch (cold-start) and idle CPU. Behavior: confirm everything still initializes/works — calendar, DND toggle, downloads, idle animations, Bluetooth, lock-screen panel, app icon, welcome sound on first launch, and notch behavior across displays.
  • Note: this is a static/behavior-preserving refactor; live verification (esp. multi-monitor + first-launch ordering) recommended.

Summary by CodeRabbit

  • Performance
    • Reduced main-thread load by offloading heavy system stats and improving network/disk baseline handling.
    • Faster media/UI updates with cached icons/thumbnails, shared timestamp parsing, and smoother visualizations (including waveform redraw improvements and timer coalescing).
  • Bug Fixes
    • Improved playback-state reliability across music services with safer main-thread updates and stronger lifecycle cleanup.
    • Prevented duplicate listeners/observers (volume and MediaRemote notifications) and stabilized lock-screen weather/calendar rendering.
  • New Features
    • Added adaptive background activity that responds to sleep, power, and thermal conditions.
    • Now-playing streaming auto-starts/stops when a supported session appears/disappears.

mehmetefeaytas and others added 21 commits July 23, 2026 23:26
…y SMC key scan

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…8601 formatter

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…main-actor media publish, stats/battery micro-opt)
…polling suspension

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… when asleep/off

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ed + debounced persistence

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…; hoist Defaults reads

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… async file reads

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…dering off the main thread + cache

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…disk enumeration

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…lineView visualizers, lazy now-playing, off-main icons, lockscreen hosting cache)
… scope re-renders

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…work

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 96ed09fb-9804-4a69-a794-572398b5fb13

📥 Commits

Reviewing files that changed from the base of the PR and between 54e159b and 129c64a.

📒 Files selected for processing (1)
  • DynamicIsland/helpers/AppIcons.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • DynamicIsland/helpers/AppIcons.swift

📝 Walkthrough

Walkthrough

The PR defers startup work, caches repeated computations and images, moves heavy metrics off the main actor, improves event-driven monitoring, and routes asynchronous media state updates through the main actor.

Changes

Performance and concurrency improvements

Layer / File(s) Summary
Startup and SwiftUI invalidation
DynamicIsland/ContentView.swift, DynamicIsland/DynamicIslandApp.swift
Stats observation and screen detection are cached, while manager initialization and launch work are deferred.
Media playback concurrency and lazy streaming
DynamicIsland/MediaControllers/*
Playback state updates use MainActor, timestamp formatters are reused, and now-playing streaming follows session presence.
Rendering, waveform, and image caching
DynamicIsland/audio/*, DynamicIsland/components/*, DynamicIsland/helpers/AppIcons.swift
Waveform, weather, thumbnail, icon, and drag-preview rendering paths are cached, deferred, or reused.
Activity-aware monitoring and system observers
DynamicIsland/managers/*, DynamicIsland/utils/CPUSensorCollector.swift
Polling adapts to system conditions, file and device observers manage lifecycle explicitly, and timers use coalescing or event-driven updates.
Fast and slow system metrics pipeline
DynamicIsland/managers/StatsManager.swift
Fast metrics remain on the main actor, while GPU, disk, and sensor collection moves to an actor with immutable snapshots; network data uses one interface snapshot.
Streaming usage and pricing initialization
DynamicIsland/managers/LLMUsage/*
JSONL files are processed incrementally, and bundled pricing is decoded off the main actor before remote pricing is fetched.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MediaRemote
  participant NowPlayingController
  participant StreamProcess
  MediaRemote->>NowPlayingController: now-playing presence notification
  NowPlayingController->>MediaRemote: query application PID
  NowPlayingController->>StreamProcess: startStreamingIfNeeded()
  MediaRemote-->>NowPlayingController: session disappears
  NowPlayingController->>StreamProcess: stopStreaming() after idle delay
Loading

Possibly related PRs

Suggested labels: in progress

Suggested reviewers: ebullioscopic

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately captures the main performance focus: scoping ContentView re-renders and deferring startup work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added the in progress This PR/issue is in progress label Jul 23, 2026
mehmetefeaytas and others added 2 commits July 24, 2026 00:44
- ThumbnailService: reconcile `cacheKeys` against the NSCache once it exceeds the
  count limit so the tracking set stays bounded; match the "<path>_" boundary in
  clearCache(for:) so invalidating /tmp/a no longer evicts /tmp/ab's thumbnails.
- BatteryActivityManager: snapshot observers (Array(values)) before invoking, so a
  callback that adds/removes observers can't trigger a mutation-during-iteration trap.
- StatsManager: preserve the network baseline when getifaddrs fails (nil snapshot)
  instead of collapsing to (0,0), which faked a speed dip and wiped previousNetworkStats.
- SystemMediaControllers: drop the volume/mute element caches — they were read/populated
  from the public API on arbitrary threads while refreshPropertyElements() cleared them on
  callbackQueue (data race). Recompute on access (cheap probe). HAL listener-leak fix retained.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
DynamicIsland/components/Shelf/Views/ShelfItemView.swift (1)

89-104: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Drag preview never updates once the real thumbnail resolves.

The removed .onChange(of: viewModel.thumbnail) was the only mechanism that refreshed cachedPreviewImage after the thumbnail loaded. Now renderDragPreview() only runs once from onAppear, using whatever viewModel.thumbnail/viewModel.icon happen to be at that moment. Since thumbnail loading (loadMetadata()) is async and can finish after this utility-priority task runs — especially for slow QuickLook generations — the composed drag preview can permanently show the generic icon fallback instead of the actual thumbnail for that shelf item.

Suggest reintroducing a thumbnail-change listener that only re-renders when the cached preview was built without a real thumbnail (to avoid regressing the "only produced once" perf goal):

🩹 Suggested fix
         .onAppear {
             Task(priority: .utility) {
                 if cachedPreviewImage == nil {
                     cachedPreviewImage = await renderDragPreview()
                 }
             }
             viewModel.onQuickLookRequest = { urls in
                 quickLookService.show(urls: urls, selectFirst: true)
             }
         }
+        .onChange(of: viewModel.thumbnail) { _, newThumbnail in
+            guard newThumbnail != nil, !renderedWithRealThumbnail else { return }
+            Task(priority: .utility) {
+                cachedPreviewImage = await renderDragPreview()
+                renderedWithRealThumbnail = true
+            }
+        }
         .quickLookPresenter(using: quickLookService)

(requires a small renderedWithRealThumbnail state flag to prevent re-rendering on every subsequent thumbnail-equal update)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/components/Shelf/Views/ShelfItemView.swift` around lines 89 -
104, Update ShelfItemView’s cached drag-preview flow around renderDragPreview
and the onAppear task by tracking whether the cached preview was rendered with a
real thumbnail, then add a thumbnail-change listener that re-renders only when
the existing preview used the fallback icon and a real thumbnail becomes
available. Preserve the current single-render behavior once a real thumbnail has
been used.
🧹 Nitpick comments (2)
DynamicIsland/DynamicIslandApp.swift (1)

952-971: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Disk I/O in the deferred block still runs on the main thread.

DispatchQueue.main.async only pushes this to the next runloop turn — idleAnimationManager.initializeDefaultAnimations() and applySelectedAppIcon() still perform synchronous disk reads on the main thread, risking a hitch right after the first frame instead of during the (already deferred) launch path. ModelPricingManager.loadInitialPricing() in this same PR already establishes the pattern of offloading to Task.detached(priority: .utility) and hopping back to main only to publish results — worth applying the same approach here for consistency and to fully avoid a post-launch stall.

♻️ Sketch: move disk I/O off the main thread
 DispatchQueue.main.async { [weak self] in
     guard let self else { return }
-
-    // Disk I/O: load bundled idle animations off the critical launch path.
-    self.idleAnimationManager.initializeDefaultAnimations()
-
-    // Disk I/O: read Defaults + load the selected icon image, then apply it.
-    applySelectedAppIcon()
-
     // Instantiate always-on managers whose init only registers
     // observers/pollers...
     _ = self.bluetoothAudioManager
     _ = self.systemTimerBridge
     _ = self.lockScreenPanelManager
 }
+
+Task.detached(priority: .utility) { [weak self] in
+    self?.idleAnimationManager.initializeDefaultAnimations()
+    let icon = /* load selected icon image data here */
+    await MainActor.run {
+        applySelectedAppIcon(with: icon)
+    }
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/DynamicIslandApp.swift` around lines 952 - 971, Move the
disk-loading work in the deferred launch
closure—idleAnimationManager.initializeDefaultAnimations() and
applySelectedAppIcon()—into a Task.detached(priority: .utility), then hop back
to the main actor only for UI or manager updates that require main-thread
access. Preserve the existing ordering and behavior, while keeping the always-on
manager materialization on the main thread.
DynamicIsland/components/Shelf/Services/ThumbnailService.swift (1)

31-44: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

cacheKeys never shrinks when NSCache auto-evicts entries.

cacheKeys is only pruned in clearCache()/clearCache(for:); NSCache's own eviction (via countLimit/totalCostLimit/memory pressure) never notifies this set, so it grows unbounded for the process lifetime even though the underlying image cache is bounded.

♻️ Use NSCacheDelegate to keep cacheKeys in sync
-actor ThumbnailService {
+actor ThumbnailService: NSObject, NSCacheDelegate {
     static let shared = ThumbnailService()
 
     private let cache: NSCache<NSString, NSImage> = {
         let cache = NSCache<NSString, NSImage>()
         cache.countLimit = 200
         cache.totalCostLimit = 64 * 1024 * 1024 // 64 MB
         return cache
     }()
+
+    func cache(_ cache: NSCache<AnyObject, AnyObject>, willEvictObject obj: Any) {
+        // remove matching key from cacheKeys
+    }

Note: actors can't directly conform to NSCacheDelegate (which requires NSObjectProtocol); this likely needs a small NSObject delegate shim that forwards to the actor.

Also applies to: 45-68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/components/Shelf/Services/ThumbnailService.swift` around lines
31 - 44, Update ThumbnailService’s cache bookkeeping so cacheKeys is removed
when NSCache evicts an object automatically. Add an NSObject-based
NSCacheDelegate shim, since the actor cannot conform directly, and have it
forward eviction callbacks to ThumbnailService; wire it to cache and keep
clearCache()/clearCache(for:) behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@DynamicIsland/components/Shelf/Services/ThumbnailService.swift`:
- Around line 75-81: Update clearCache(for:) so cache key matching only removes
the requested file path or entries within its directory, requiring a
path-component boundary after url.path rather than a raw string prefix. Preserve
removal through cache.removeObject and cacheKeys.remove for each valid match.

In `@DynamicIsland/helpers/AppIcons.swift`:
- Around line 49-56: Update getIcon(bundleID:) to retain the resolved
application URL and pass its .path to getIcon(file:), rather than using
.absoluteString, so downstream filesystem APIs receive a POSIX path.

---

Outside diff comments:
In `@DynamicIsland/components/Shelf/Views/ShelfItemView.swift`:
- Around line 89-104: Update ShelfItemView’s cached drag-preview flow around
renderDragPreview and the onAppear task by tracking whether the cached preview
was rendered with a real thumbnail, then add a thumbnail-change listener that
re-renders only when the existing preview used the fallback icon and a real
thumbnail becomes available. Preserve the current single-render behavior once a
real thumbnail has been used.

---

Nitpick comments:
In `@DynamicIsland/components/Shelf/Services/ThumbnailService.swift`:
- Around line 31-44: Update ThumbnailService’s cache bookkeeping so cacheKeys is
removed when NSCache evicts an object automatically. Add an NSObject-based
NSCacheDelegate shim, since the actor cannot conform directly, and have it
forward eviction callbacks to ThumbnailService; wire it to cache and keep
clearCache()/clearCache(for:) behavior unchanged.

In `@DynamicIsland/DynamicIslandApp.swift`:
- Around line 952-971: Move the disk-loading work in the deferred launch
closure—idleAnimationManager.initializeDefaultAnimations() and
applySelectedAppIcon()—into a Task.detached(priority: .utility), then hop back
to the main actor only for UI or manager updates that require main-thread
access. Preserve the existing ordering and behavior, while keeping the always-on
manager materialization on the main thread.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 851f911a-d899-49b3-a35b-f3ee57020d31

📥 Commits

Reviewing files that changed from the base of the PR and between 503606c and 045fb5d.

📒 Files selected for processing (28)
  • DynamicIsland/ContentView.swift
  • DynamicIsland/DynamicIslandApp.swift
  • DynamicIsland/MediaControllers/AmazonMusicController.swift
  • DynamicIsland/MediaControllers/AppleMusicController.swift
  • DynamicIsland/MediaControllers/NowPlayingController.swift
  • DynamicIsland/MediaControllers/SpotifyController.swift
  • DynamicIsland/MediaControllers/YouTube Music Controller/YouTubeMusicController.swift
  • DynamicIsland/audio/RealTimeAudioSpectrum.swift
  • DynamicIsland/components/LockScreen/LockScreenWeatherWidget.swift
  • DynamicIsland/components/Music/MusicVisualizer.swift
  • DynamicIsland/components/Music/RealTimeWaveformScrubberView.swift
  • DynamicIsland/components/Shelf/Services/ThumbnailService.swift
  • DynamicIsland/components/Shelf/ViewModels/ShelfItemViewModel.swift
  • DynamicIsland/components/Shelf/Views/ShelfItemView.swift
  • DynamicIsland/helpers/AppIcons.swift
  • DynamicIsland/managers/ActivityGate.swift
  • DynamicIsland/managers/BatteryActivityManager.swift
  • DynamicIsland/managers/BluetoothAudioManager.swift
  • DynamicIsland/managers/ClipboardManager.swift
  • DynamicIsland/managers/DoNotDisturbManager.swift
  • DynamicIsland/managers/LLMUsage/JSONLUsageParser.swift
  • DynamicIsland/managers/LLMUsage/ModelPricingManager.swift
  • DynamicIsland/managers/LockScreenWeatherPanelManager.swift
  • DynamicIsland/managers/MediaKeyInterceptor.swift
  • DynamicIsland/managers/StatsManager.swift
  • DynamicIsland/managers/SystemMediaControllers.swift
  • DynamicIsland/managers/SystemTimerBridge.swift
  • DynamicIsland/utils/CPUSensorCollector.swift

Comment thread DynamicIsland/components/Shelf/Services/ThumbnailService.swift
Comment thread DynamicIsland/helpers/AppIcons.swift
mehmetefeaytas and others added 3 commits July 24, 2026 00:51
- ClipboardManager: replace `MainActor.assumeIsolated` in the poll tick (which would
  trap if the timer ever ran off the main thread) with a plain Bool cached from a
  main-actor subscription to `ActivityGate.$shouldSuspendBackgroundWork`.
- DoNotDisturbManager: confine all Assertions dispatch-source lifecycle to `pollingQueue`.
  start/stop were mutating the `assertions*Source` vars on the main thread while the
  filesystem-event handlers re-armed them on `pollingQueue` — a data race.

(Also carries the phase-1 CodeRabbit fixes via merge: ThumbnailService cacheKeys/boundary,
BatteryActivityManager snapshot, StatsManager network baseline, SystemMediaControllers cache revert.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AppIcons.getIcon(bundleID:): use `appURL.path` instead of `.absoluteString`. The
  getIcon(file:) guard uses fileExists(atPath:), which only accepts POSIX paths, so the
  "file://…" form made the bundle-ID lookup always return nil.
- JSONLUsageParser: replace the per-line `removeSubrange` (which shifted the whole
  buffer for every newline → quadratic on newline-dense JSONL) with a chunk cursor that
  emits lines via slices and trims the consumed prefix once per chunk.

(Carries the phase-1/2 CodeRabbit fixes via merge — incl. ThumbnailService cacheKeys/boundary
and SystemMediaControllers cache revert that Ebullioscopic#655 also flagged.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
DynamicIsland/helpers/AppIcons.swift (1)

23-38: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Invalidate cached icons when applications change.

The cache is keyed only by file path and has no explicit invalidation. If an app is updated or replaced at the same path while this process remains running, callers can receive the old icon indefinitely. Include the bundle version/modification state in the cache key or invalidate entries when application changes are detected.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@DynamicIsland/helpers/AppIcons.swift` around lines 23 - 38, The
cachedIcon(forFile:) implementation must avoid returning stale icons after an
application changes at the same path. Incorporate the app bundle’s version or
modification state into the NSCache key, or add equivalent change detection that
invalidates the affected entry before lookup, while preserving the existing
NSWorkspace icon resolution and caching behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@DynamicIsland/helpers/AppIcons.swift`:
- Around line 23-38: The cachedIcon(forFile:) implementation must avoid
returning stale icons after an application changes at the same path. Incorporate
the app bundle’s version or modification state into the NSCache key, or add
equivalent change detection that invalidates the affected entry before lookup,
while preserving the existing NSWorkspace icon resolution and caching behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b422321-bfca-4aab-ab01-7bb46196e078

📥 Commits

Reviewing files that changed from the base of the PR and between 045fb5d and dd4f5bc.

📒 Files selected for processing (8)
  • DynamicIsland/components/Shelf/Services/ThumbnailService.swift
  • DynamicIsland/helpers/AppIcons.swift
  • DynamicIsland/managers/BatteryActivityManager.swift
  • DynamicIsland/managers/ClipboardManager.swift
  • DynamicIsland/managers/DoNotDisturbManager.swift
  • DynamicIsland/managers/LLMUsage/JSONLUsageParser.swift
  • DynamicIsland/managers/StatsManager.swift
  • DynamicIsland/managers/SystemMediaControllers.swift
🚧 Files skipped from review as they are similar to previous changes (7)
  • DynamicIsland/managers/BatteryActivityManager.swift
  • DynamicIsland/managers/LLMUsage/JSONLUsageParser.swift
  • DynamicIsland/components/Shelf/Services/ThumbnailService.swift
  • DynamicIsland/managers/DoNotDisturbManager.swift
  • DynamicIsland/managers/SystemMediaControllers.swift
  • DynamicIsland/managers/StatsManager.swift
  • DynamicIsland/managers/ClipboardManager.swift

mehmetefeaytas and others added 2 commits July 24, 2026 01:25
Address CodeRabbit review on Ebullioscopic#656: the deferred launch block used
DispatchQueue.main.async, which only pushes work to the next runloop
turn — the app-icon image read (NSImage(contentsOf:)) still hit disk on
the main thread, moving a potential hitch to just after the first frame
instead of off-main.

Split the icon load into a pure, off-main-safe loadSelectedAppIconImage()
(Defaults lookup + disk read, no UI) and assign applicationIconImage back
on the main actor from a Task.detached(.utility), matching the existing
ModelPricingManager.loadInitialPricing() pattern.

initializeDefaultAnimations() stays on the main actor by design: it only
resolves bundled resource URLs (no file-content reads) and writes Defaults
keys that have UI observers, so offloading it would risk off-main UI updates.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address CodeRabbit review on Ebullioscopic#656: appIconPathCache was keyed by file
path alone, so once an icon was cached for a path it was returned for the
process lifetime. If the app at that path was updated/replaced while Atoll
kept running, callers received the stale icon indefinitely.

Fold the file's modification date into the cache key. When the bundle
changes its mtime changes, the key changes, and a fresh NSWorkspace icon
is resolved. stat() is far cheaper than icon(forFile:), so the cache still
avoids the expensive lookup on every SwiftUI refresh.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in progress This PR/issue is in progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant